package com.example.security;

import cn.hutool.json.JSONUtil;
import com.example.domain.po.LoginUserDetails;
import com.example.utils.JwtUtils;
import com.example.utils.RedisClient;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

/**
 * 自定义过滤器，实现token令牌的判断
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    //OncePerRequestFilter: spingboot内置过滤器

    private final RedisClient redisClient;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //获取请求头
        String token = request.getHeader("token");

        String requestUrl = request.getRequestURI();
        //验证Jwt是否过期
        // 判断token是否存在,如果不存在,说明未登录,返回错误信息
        //1. 判断是否包含login,register,包含说明是登录/注册操作,不校验 token
        if (requestUrl.contains("/login")|| requestUrl.contains("/register")) {
            log.info("登录操作,放行");
        }else {
            if (token == null || token.isEmpty()) {
                log.info("令牌为空,未登录");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);// 401
                return;
            }
            //2.如果存在,校验令牌是否正确/过期
            try {
                JwtUtils.verify(token);
            } catch (Exception e) {
                //3.如果令牌非法,删除redis中的令牌
                String key="login:token:"+token;
                if(redisClient.exists(key))
                    redisClient.del(key);
                //响应401
                log.info("令牌非法,响应401");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);// 401
                return;
            }
            //4.校验通过,放行
            log.info("令牌校验通过,放行");
        }

        //获取用户信息,送入SpringSecurity上下文
        if(StringUtils.hasLength(token)){
            //redis中获取用户信息
            String key = "login:token:"+token;
            String json = redisClient.get(key);
            if(StringUtils.hasLength(json)){
                //反序列化
                LoginUserDetails userDetails = JSONUtil.toBean(json, LoginUserDetails.class);
                if(Objects.nonNull(userDetails)){
                    //封装用户信息,送到下一个过滤器  UsernamePasswordAuthenticationFilter
                    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
                    //将Redis数据库中的信息送到SpringSecurity上下文中
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                }else {
                    SecurityContextHolder.getContext().setAuthentication(null);
                }
            }
        }
        //放行,后面交给Spring Security 框架
        filterChain.doFilter(request,response);
    }
}
